﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace T1AdsSimuladorV1
{
   // enum EventoAtual { che, intra, feedback, sa1, sa2 };
    public partial class SimuladorMain : Form
    {
        public List<Evento> listaEventosAgendados;
        float timeElapsed;
        int pc_che;
        int pc_intra;
        int pc_feedback;
        int pc_sa1;
        int pc_sa2;
        Evento eventoAtual;
        int indexLastGlobal = 0;

        int indexNewGlobal = 0;
       

        public SimuladorMain()
        {
            InitializeComponent();
            listaEventosAgendados = new List<Evento>();
            populaColunasBasicas();
            timeElapsed=0F;
            pc_che = 0;
            pc_intra = 0;
            pc_feedback = 0;
            pc_sa1 = 0;
            pc_sa2 = 0;
            eventoAtual = new Evento();
            eventoAtual.ID = 1;
        }

        private void populaColunasBasicas() {
            dataGridSimulador.Columns.Clear();
            dataGridSimulador.Columns.Add("Evento", "Evento");
            dataGridSimulador.Columns.Add("Fila1", "Fila1");
            dataGridSimulador.Columns.Add("Fila2", "Fila2");
            dataGridSimulador.Columns.Add("Tempo", "Tempo");
            
            for (int i = 0; i <= Int32.Parse(txtFilaKapacidade.Text); i++) {
                dataGridSimulador.Columns.Add(i.ToString()+"_Fila1", i.ToString()+"_Fila1");
            }

            for (int i = 0; i <= Int32.Parse(txtFila2Kapacidade.Text); i++)
            {
                dataGridSimulador.Columns.Add(i.ToString()+"_Fila2", i.ToString()+"_Fila2");
            }

            populaColunasEventosAgendados();
        }

        private void populaColunasEventosAgendados()
        {
            dataGridEventosAgendados.Columns.Clear();
            dataGridEventosAgendados.Columns.Add("id", "id");
            dataGridEventosAgendados.Columns.Add("Evento","Evento");
            dataGridEventosAgendados.Columns.Add("Tempo", "Tempo");
            dataGridEventosAgendados.Columns.Add("Sorteio", "Sorteio");
            dataGridEventosAgendados.Columns.Add("Executado", "Executado");
        }

        private void btnPseudoRandomicos_Click(object sender, EventArgs e)
        {
            if (txtSemente.Text.Length == 0 || 
                    ( cmbQuantidadeAleatorio.Text.Length == 0 && 
                        ( cmbQuantidadeAleatorio.SelectedItem != null && 
                           cmbQuantidadeAleatorio.SelectedItem.ToString().Length == 0
                        )
                    )
                )
                return;

            IGerador gerador = null;
            if (radioQuadradosMedios.Checked == true)
                gerador = new QuadradosMedios();
            else //TODO congruente Linear
                throw new NotImplementedException();
            try
            {
                gerador.X0_semente = Int16.Parse(txtSemente.Text);
                int qtd = 0;
                if (cmbQuantidadeAleatorio.SelectedItem == null)
                    qtd = Int16.Parse(cmbQuantidadeAleatorio.Text);
                else
                    qtd = Int16.Parse(cmbQuantidadeAleatorio.SelectedItem.ToString());
                foreach (float value in gerador.generate(qtd))
                    listNumerosGerados.Items.Add(value);
            }
            catch (Exception ex)
            {
                System.Windows.Forms.MessageBox.Show("Falha ao gerar: " + ex.ToString());
            }
        }

        private void txtSemente_Click(object sender, EventArgs e)
        {
            if (txtSemente.Text.CompareTo("Semente") == 0)
                txtSemente.Text = String.Empty;
        }

        private void txtFilaKapacidade_TextChanged(object sender, EventArgs e)
        {
            String temp = (String)listExecution.Items[1];
            temp = temp.Replace(temp.Split('<')[1].Trim(), txtFilaKapacidade.Text);
            listExecution.Items[1] = temp;
            populaColunasBasicas();
        }

        private void btnAvanca_Click(object sender, EventArgs e)
        {
            if (listaEventosAgendados.Count == 0)
            {
                timeElapsed = 0;
                agendaEvento(Evento.TipoEvento.che, txtLambdaCHE.Text, Double.Parse(txtTempoInicial.Text));
                int indexNew = dataGridSimulador.Rows.Add(1);
                dataGridSimulador.Rows[indexNew].Cells["Evento"].Value = "-";
                dataGridSimulador.Rows[indexNew].Cells["Fila1"].Value = "0";
                dataGridSimulador.Rows[indexNew].Cells["Fila2"].Value = "0";
                dataGridSimulador.Rows[indexNew].Cells["Tempo"].Value = "0";

                for (int i = 0; i <= int.Parse(txtFilaKapacidade.Text); i++)
                    dataGridSimulador.Rows[indexNew].Cells[i.ToString() + "_Fila1"].Value = "0";
                for (int i = 0; i <= int.Parse(txtFila2Kapacidade.Text); i++)
                    dataGridSimulador.Rows[indexNew].Cells[i.ToString() + "_Fila2"].Value = "0";
           }
           
            refreshListsBoxes();

            switch(eventoAtual.evento)
            {
                case Evento.TipoEvento.che:
                    execChe();
                    break;
                case Evento.TipoEvento.feedback:
                    execFeedback();
                    break;
                case Evento.TipoEvento.intra:
                    execIntra();
                    break;
                case Evento.TipoEvento.sa1:
                    execSa1();
                    break;
                case Evento.TipoEvento.sa2:
                    execSa2();
                    break;
            }
            
        }

        private void selecionaProximoEvento()
        {
            dataGridEventosAgendados.Rows[eventoAtual.indexRowAtual].Cells["Executado"].Value = "Sim";
            List<float> tempoAgendado = new List<float>();
            int linhaProximoEvento = 0;
            float proxMenor = 10000;
            foreach (DataGridViewRow row in dataGridEventosAgendados.Rows)
            {
                if (row.Cells["Tempo"].Value != null && row.Cells["Executado"].Value != null && row.Cells["Executado"].Value.ToString() != "Sim")
                {
                    if (proxMenor > float.Parse(row.Cells["Tempo"].Value.ToString()))
                    {
                        proxMenor = float.Parse(row.Cells["Tempo"].Value.ToString());
                        linhaProximoEvento = row.Index;
                        
                    }
                }
            }
            
            DataGridViewRow temp_row = dataGridEventosAgendados.Rows[linhaProximoEvento];
            eventoAtual.ID = int.Parse(temp_row.Cells["id"].Value.ToString()); 
            eventoAtual.sorteio = Double.Parse(temp_row.Cells["Sorteio"].Value.ToString());
            eventoAtual.tempo = Double.Parse(temp_row.Cells["Tempo"].Value.ToString());
            eventoAtual.evento = (Evento.TipoEvento)Enum.Parse(typeof(Evento.TipoEvento), temp_row.Cells["Evento"].Value.ToString());
            eventoAtual.indexRowAtual = linhaProximoEvento;
        }

        private void execSa2()
        {
            switch (pc_sa2)
            {
                case 0:
                    float tempoProcessamento = U(txtLambdaSA2.Text);
                    timeElapsed = timeElapsed + tempoProcessamento;
                    contabilizarFilas(tempoProcessamento);
                    pc_sa2++;
                    break;
                case 1:
                    subFila(2);
                    pc_sa2 = 0;
                    selecionaProximoEvento();
                    break;
            }
        }

        private void execSa1()
        {
            switch (pc_sa1)
            {
                case 0:
                    float tempoProcessamento = U(txtLambdaSA2.Text);
                    timeElapsed = timeElapsed + tempoProcessamento;
                    contabilizarFilas(tempoProcessamento);
                    pc_sa1++;
                    break;
                case 1:
                    subFila(1);
                    pc_sa1 = 0;
                    selecionaProximoEvento();
                    break;
            }
        }

        private void execIntra()
        {
            switch (pc_intra)
            {
                case 0:
                    float tempoProcessamento = U(txtLambdaSA2.Text);
                    timeElapsed = timeElapsed + tempoProcessamento;
                    contabilizarFilas(tempoProcessamento);
                    pc_intra++;
                    break;
                case 1:
                    subFila(1);
                    pc_intra++;
                    break;
                case 2:
                    if (filaCount(2) < Int32.Parse(txtFila2Kapacidade.Text))
                        pc_intra++;
                    else
                        pc_intra = 9; //jump to last line
                    break;
                case 3:
                    addFila(2);
                    pc_intra++;
                    break;
                case 4:
                    {
                        if (U("0,1") < 0.5)
                            pc_intra++;
                        else
                            pc_intra = 4;
                    }
                    break;
                case 5:
                    agendaEvento(Evento.TipoEvento.feedback, txtLambdaFeed.Text, timeElapsed);
                    pc_intra = 8;
                    break;
                case 6:
                    pc_intra++;
                    break;
                case 7:
                    agendaEvento(Evento.TipoEvento.sa2, txtLambdaSA2.Text, timeElapsed);
                    pc_intra++;
                    break;
                case 8:
                    pc_intra++;
                    break;
                case 9:
                    pc_intra = 0;
                    selecionaProximoEvento();
                    break;
            }
        }

        private void execFeedback()
        {
            switch (pc_feedback)
            {
                case 0:
                    float tempoProcessamento = U(txtLambdaSA2.Text);
                    timeElapsed = timeElapsed + tempoProcessamento;
                    contabilizarFilas(tempoProcessamento);
                    pc_feedback++;
                    break;
                case 1:
                    subFila(2);
                    pc_feedback++;
                    break;
                case 2:
                    pc_feedback = 0;
                    selecionaProximoEvento();
                    break;
            }
        } 
            
        void refreshListsBoxes()
        {
            listExecution.SelectedIndex = pc_che;
            listFeedbackExecution.SelectedIndex = pc_feedback;
            listIntraExecution.SelectedIndex = pc_intra;
            lstSa1Exec.SelectedIndex = pc_sa1;
            listSA2Execution.SelectedIndex = pc_sa2;
        }

        private int filaCount(int fila)
        {
            int indexLastlocal = dataGridSimulador.Rows.GetLastRow(new DataGridViewElementStates());
            if (dataGridSimulador.Rows[indexLastGlobal].Cells["Fila1"].Value.ToString() == "")
                return -1;

            if(fila == 1)
                return int.Parse(dataGridSimulador.Rows[indexLastGlobal].Cells["Fila1"].Value.ToString());
            else
                return int.Parse(dataGridSimulador.Rows[indexLastGlobal].Cells["Fila2"].Value.ToString());
        }


        private void execChe()
        {
            switch (pc_che)
            {
                case 0:
                    {
                        float tempoProcessamento = float.Parse(txtTempoInicial.Text);
                        if (timeElapsed == 0)
                            timeElapsed = Int32.Parse(txtTempoInicial.Text);
                        else
                        {
                            tempoProcessamento = U(txtLambdaSA2.Text);
                            timeElapsed = timeElapsed + tempoProcessamento;
                        }
                        contabilizarFilas(tempoProcessamento);
                        pc_che++;
                    }
                    break;
                case 1:
                    if (filaCount(1) < Int32.Parse(txtFilaKapacidade.Text))
                        pc_che++;
                    else
                        pc_che = 9; //jump to last line
                    break;
                case 2:
                    addFila(1);
                    pc_che++;
                    break;
                case 3:
                    {
                        if (U("0,1") < 0.8)
                            pc_che++;
                        else
                            pc_che = 5;
                    }
                    break;
                case 5:
                    pc_che++;
                    break;
                case 4:
                    agendaEvento(Evento.TipoEvento.intra, txtLambdaINTRA.Text, timeElapsed);
                    pc_che = 7;
                    break;
                case 6:
                    agendaEvento(Evento.TipoEvento.sa1, txtLambdaSA1.Text, timeElapsed);
                    pc_che++;
                    break;
                case 7:
                case 8:
                    pc_che++;
                    break;
                case 9:
                    agendaEvento(Evento.TipoEvento.che, txtLambdaCHE.Text, timeElapsed);
                    pc_che = 0;
                    selecionaProximoEvento();
                    break;
            }
            refreshListsBoxes();
            
        }

        public void addFila(int fila)
        {
//            int indexLast = dataGridSimulador.Rows.GetLastRow(new DataGridViewElementStates())-1;
            if (fila == 1)
            {
                int temp = Int32.Parse(dataGridSimulador.Rows[indexLastGlobal].Cells["Fila1"].Value.ToString());
                temp += 1;
                dataGridSimulador.Rows[indexNewGlobal].Cells["Fila1"].Value = temp.ToString();
                dataGridSimulador.Rows[indexNewGlobal].Cells["Fila2"].Value =
                    Int32.Parse(dataGridSimulador.Rows[indexLastGlobal].Cells["Fila2"].Value.ToString());
            }
            else if (fila == 2)
            {
                int temp = Int32.Parse(dataGridSimulador.Rows[indexLastGlobal].Cells["Fila2"].Value.ToString());
                temp += 1;
                dataGridSimulador.Rows[indexNewGlobal].Cells["Fila2"].Value = temp.ToString();
                dataGridSimulador.Rows[indexNewGlobal].Cells["Fila1"].Value =
                    Int32.Parse(dataGridSimulador.Rows[indexLastGlobal].Cells["Fila1"].Value.ToString());
            }
        }

        public void subFila(int fila)
        {
            //int indexLast = dataGridSimulador.Rows.GetLastRow(new DataGridViewElementStates());
            if (fila == 1)
            {
                int temp = Int32.Parse(dataGridSimulador.Rows[indexLastGlobal].Cells["Fila1"].Value.ToString());
                temp -= 1;
                dataGridSimulador.Rows[indexNewGlobal].Cells["Fila1"].Value = temp.ToString();
                dataGridSimulador.Rows[indexNewGlobal].Cells["Fila2"].Value =
                   Int32.Parse(dataGridSimulador.Rows[indexLastGlobal].Cells["Fila2"].Value.ToString());
            }
            else if (fila == 2)
            {
                int temp = Int32.Parse(dataGridSimulador.Rows[indexLastGlobal].Cells["Fila2"].Value.ToString());
                temp -= 1;
                dataGridSimulador.Rows[indexNewGlobal].Cells["Fila2"].Value = temp.ToString();
                dataGridSimulador.Rows[indexNewGlobal].Cells["Fila1"].Value =
                    Int32.Parse(dataGridSimulador.Rows[indexLastGlobal].Cells["Fila1"].Value.ToString());
            }
        }

        public void contabilizarFilas(float tempo)
        {
            int fila1 = filaCount(1);
            int fila2 = filaCount(2);
            indexLastGlobal = dataGridSimulador.Rows.GetLastRow(new DataGridViewElementStates()) - 1 ;

            indexNewGlobal = dataGridSimulador.Rows.Add(1);
            dataGridSimulador.Rows[indexNewGlobal].Cells["Evento"].Value = eventoAtual.ID + "-" + eventoAtual.evento.ToString();
            dataGridSimulador.Rows[indexNewGlobal].Cells["Fila1"].Value = "";
            dataGridSimulador.Rows[indexNewGlobal].Cells["Fila2"].Value = "";
            dataGridSimulador.Rows[indexNewGlobal].Cells["Tempo"].Value = tempo.ToString();

            for (int i = 0; i <= int.Parse(txtFilaKapacidade.Text); i++)
                dataGridSimulador.Rows[indexNewGlobal].Cells[i.ToString() + "_Fila1"].Value = "0";
            for (int i = 0; i <= int.Parse(txtFila2Kapacidade.Text); i++)
                dataGridSimulador.Rows[indexNewGlobal].Cells[i.ToString() + "_Fila2"].Value = "0";

            dataGridSimulador.Rows[indexNewGlobal].Cells[fila1.ToString() + "_Fila1"].Value =
                float.Parse(dataGridSimulador.Rows[indexLastGlobal].Cells[fila1.ToString() + "_Fila1"].Value.ToString())
                + tempo;
            dataGridSimulador.Rows[indexNewGlobal].Cells[fila2.ToString() + "_Fila2"].Value =
                float.Parse(dataGridSimulador.Rows[indexLastGlobal].Cells[fila2.ToString() + "_Fila2"].Value.ToString())
                + tempo;
            
            
        }

        public float U(String intervalo)
        {
            if (listNumerosGerados.Items.Count == 0)
                return -1;
            float aleatorio = float.Parse(listNumerosGerados.Items[0].ToString());
            listNumerosGerados.Items.RemoveAt(0);
            String[] ab = intervalo.Split(',');
            int a = Int32.Parse(ab[0]);
            int b = Int32.Parse(ab[1]);
            float temp = (b-a) * aleatorio + a;
            return temp;
        }

        public void agendaEvento(T1AdsSimuladorV1.Evento.TipoEvento nome, String intervalo, Double tempo)
        {
            Evento evento = new Evento();
            evento.evento = nome;
            evento.tempo = tempo;
            evento.sorteio = U(intervalo);
            evento.ID = incrementaId();
            if (evento.sorteio == -1)
            {
                System.Windows.Forms.MessageBox.Show("Sem números pseudo-aleatorios, fim da simulacao");
                return;
            }
            if (listaEventosAgendados.Count > 0)
                evento.tempo = tempo + evento.sorteio;
            else
                evento.tempo = tempo;

            listaEventosAgendados.Add(evento);
            dataGridEventosAgendados.Rows.Add(new String[] {evento.ID.ToString(),evento.evento.ToString(),evento.tempo.ToString(),evento.sorteio.ToString(), "Não" });
            
        }

        private int incrementaId()
        {
            int maxid = 0;
            foreach (DataGridViewRow row in dataGridEventosAgendados.Rows)
            {
                if (row.Cells["id"] == null || row.Cells["id"].Value == null)
                    continue;
                
                if(maxid < int.Parse(row.Cells["id"].Value.ToString()))
                    maxid = int.Parse(row.Cells["id"].Value.ToString());
            }
            return maxid+1;
        }

        private void txtFila2Kapacidade_TextChanged(object sender, EventArgs e)
        {
            populaColunasBasicas();
        }

        private void SimuladorMain_Load(object sender, EventArgs e)
        {

        }
    }
}
